﻿using Abp.Authorization;
using Abp.Runtime.Session;
using Abp.Specifications;
using Abp.UI;
using Paas.App.Interface.Common;
using Paas.App.Interface.Common.Dtos;
using Paas.App.Interface.Common.Messages;
using Paas.Core;
using Paas.Core.Common.Entities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Basefr.App;
using Basefr.Core.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Paas.App.Common
{
    [Route("Announcement")]
    [AbpAuthorize()]
    public class AnnouncementAppService : AppService, IAnnouncementAppService
    {
        private readonly IMainRepository<Announcement> _announcementRepo;
        private readonly IMainRepository<AnnouncementAttach> _attachRepo;
        private readonly IMainRepository<File> _fileRepo;

        public AnnouncementAppService(IMainRepository<Announcement> announcementRepo, IMainRepository<AnnouncementAttach> attachRepo, IMainRepository<File> fileRepo)
        {
            _announcementRepo = announcementRepo;
            _attachRepo = attachRepo;
            _fileRepo = fileRepo;
        }

        [HttpPost(nameof(SearchAnnouncement))]
        public virtual SearchAnnouncementOutput SearchAnnouncement(SearchAnnouncementInput input)
        {
            Expression<Func<Announcement, bool>> predicate = p => true;

            if (!string.IsNullOrWhiteSpace(input.Keyword))
            {
                var keyword = input.Keyword.Trim();
                predicate = predicate.And(p => p.Title.Contains(keyword) || p.Content.Contains(keyword));
            }

            var result = _announcementRepo.GetAll()
                .Include(p => p.Poster)
                .Include(p => p.Attaches).ThenInclude(p => p.File)
                .Where(predicate)
                .OrderByDescending(p => p.Id)
                .GetPage(input.SkipCount, input.MaxResultCount, out var total, out var isOverPaged)
                .ToList();

            return new SearchAnnouncementOutput { Items = ObjectMapper.Map<List<AnnouncementDto>>(result), TotalCount = total, IsOverPaged = isOverPaged };
        }

        [HttpPost(nameof(SaveAnnouncement))]
        public virtual SaveAnnouncementOutput SaveAnnouncement(SaveAnnouncementInput input)
        {
            input.Item.Title = input.Item.Title.Trim();
            input.Item.Content = input.Item.Content.Trim();

            input.AttachIds ??= new List<int>();

            if (_announcementRepo.GetAll().Any(p => p.Id != input.Item.Id && p.Title == input.Item.Title))
            {
                throw new UserFriendlyException("系统公告标题不能重复，已存在相同的公告标题");
            }

            if (input.Item.Id <= 0)
            {
                var entity = ObjectMapper.Map<Announcement>(input.Item);

                entity.PosterId = AbpSession.GetUserId();

                _announcementRepo.Insert(entity);

                if (input.AttachIds.Any())
                {
                    input.AttachIds.ForEach(id => _attachRepo.Insert(new AnnouncementAttach { Announcement = entity, FileId = id }));
                }

                return new SaveAnnouncementOutput();
            }

            var exist = _announcementRepo.GetAll().Include(p => p.Attaches).First(input.Item.Id);

            exist.Title = input.Item.Title;
            exist.Content = input.Item.Content;

            var deleteAttaches = exist.Attaches.FindAll(a => input.AttachIds.All(id => a.Id != id));

            if (deleteAttaches.Any())
            {
                _attachRepo.Delete(deleteAttaches);
            }

            input.AttachIds.ForEach(id =>
            {
                if (exist.Attaches.All(a => a.Id != id))
                {
                    _attachRepo.Insert(new AnnouncementAttach { Announcement = exist, FileId = id });
                }
            });

            return new SaveAnnouncementOutput();
        }

        [HttpPost(nameof(DeleteAnnouncement))]
        public virtual DeleteAnnouncementOutput DeleteAnnouncement(DeleteAnnouncementInput input)
        {
            var item = _announcementRepo.Get(input.Id);

            _announcementRepo.Delete(item);

            return new DeleteAnnouncementOutput();
        }
    }
}

